package input;

import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.JFrame;

import org.math.plot.Plot2DPanel;
import org.math.plot.Plot3DPanel;

import application.Application;
import application.FileManager;
import edu.emory.mathcs.jtransforms.dct.DoubleDCT_1D;

public class DCT implements Runnable{
	
	//double[] caleWejscie;
	
	private ArrayList<double[]> ffts;
	private double[][] atr;
	
	private byte[] in;
	private double[] x, y, z;
	
	private DoubleDCT_1D dct;
	
	public int n = 1024; 	//rozdzielczosc transformaty
	private int div = 3; 	//jaka czesc z n bierzemy np. 1024/3 = 341
	private int len = 4410;	//dlugosc ramki
	
	private boolean dataLoaded;
	private boolean ready = false;;
	private boolean current;
	
	
	public DCT() {
		dct = new DoubleDCT_1D(n);
		Application.k.out("DCT gotowa! (1/"+div+" z "+n+")");
	}
	
	
	public void loadData(byte[] in){
		if(in != null && in.length > 0){
			dataLoaded = true;
			current = false;
			this.in = in;
		}
	}
	
	public void run(){

		ffts = new ArrayList<double[]>();
		
		double[] a = new double[len];
		
		int off = 0;
		while(off+len <= in.length){
			double[] temp = new double[n];	// dlugosc trasf.
			
			for(int i = off; i < off+len; i++){
				a[i-off] = in[i];
			}

			dct.forward(a, true);
			
			for(int i = 0; i < n; i++) {
				temp[i] = a[i];
			}
		
			ffts.add(temp);
			off += len;
		}
		
		attribs();
		Application.k.out("DCT ok! "+ffts.size()+" frames.");
		current = true;
		ready = true;
	}


	public boolean isReady(){
		return ready;
	}
	
	public boolean dataLoaded(){
		return dataLoaded;
	}
	
	public boolean isCurrent(){
		return current;
	}
	
	private void attribs(){
		x = new double[ffts.size()*(n/div)];
		y = new double[ffts.size()*(n/div)];
		z = new double[ffts.size()*(n/div)];
		
		int i = 0;
		int t = 0;
		double k = 6;
		
		for (double[] d : ffts) {
			for (int j = 1; j < d.length / div; j++){
				//z1[i] = d[j]/240;
				
				double m2, m1, c, p1, p2;
				
				c =  1.00 * Math.abs(Math.atan(d[j]/k)/(Math.PI/2));
				m2 = 0.25 * (j > 1 ?  Math.abs(Math.atan(d[j-2]/k)/(Math.PI/2)) : c);
				m1 = 0.75 * (j > 0 ?  Math.abs(Math.atan(d[j-1]/k)/(Math.PI/2)) : c);
				p1 = 0.75 * (j < d.length / div - 1 ?  Math.abs(Math.atan(d[j+1]/k)/(Math.PI/2)) : c);
				p2 = 0.25 * (j < d.length / div - 2 ? Math.abs(Math.atan(d[j+1]/k)/(Math.PI/2)) : c);
				
				z[i] = (m2 + m1 + c + p1 + p2)/3.0;
				x[i] = j;
				y[i] = t;
				i++;
				//integers[j] = Math.abs(d[j]) > integers[j] ? Math.abs(d[j]) : integers[j];
			}
			t++;
		}
		

		//0:max, 1:avr, 2:median, 3:std_var, 4:0.2 percentile, 5:gdzie jest max (w czasie)
		atr = new double[6][n/div];
		
		int ramek = ffts.size();
		//System.out.println("ramek = "+ramek);

		for (int j = 0; j < (n/div); j++) {
			for(int ramka = 0; ramka < ramek; ramka++){
				int index = ramka*(n/div)+j;
				
				if(z[index] > atr[0][j]){
					atr[0][j] = z[index];
					atr[5][j] = ((double) ramka)/ (double) ramek;
				}
				
				atr[1][j] += z[index]; //sum
			}
		}
		
		for (int j = 0; j < (n/div); j++) {
			atr[1][j] /= ramek; //avg
		}

		for (int j = 0; j < (n/div); j++) {
			for(int ramka = 0; ramka < ramek; ramka++){
				int index = ramka*(n/div)+j;
				atr[3][j] += Math.pow(atr[1][j] - z[index], 2); //std_dev
				atr[4][j] += z[index] > 0.2 ? 1 : 0; //0.2 percentile
				//atr[5][j] += z[index] > 0.5 ? 1 : 0; //0.5 percentile
			}
		}
		
		for (int j = 0; j < (n/div); j++) {
			atr[3][j] = Math.pow(atr[3][j]/ramek, 0.5); //std_dev
			atr[4][j] /= ramek;
			//atr[5][j] /= ramek;
		}
		

		for (int j = 0; j < (n/div); j++) {
			double[] temp = new double[ramek];
			
			for(int ramka = 0; ramka < ramek; ramka++){
				int index = ramka*(n/div)+j;
				temp[ramka] = z[index];
			}
			
			Arrays.sort(temp);
			atr[2][j] = temp[ramek/2];
		}
		
	}
	
	public void saveToFile(String name){

		String[] data = new String[6];
		
		for (int a = 0; a < 6; a++) {
			StringBuilder sb = new StringBuilder(); 
			
			for(int j = 0; j < (n/div); j++){
				
				sb.append(atr[a][j]);
				sb.append(' ');
			}
			
			data[a] = sb.toString();
		}
		
		FileManager am = FileManager.getInstance();
		am.saveToFile(name, data);
	}
	
	public double[] getAttribs(){
		double[] ret = new double[atr.length*atr[0].length];
		
		int atrCount = atr.length;
		int atrLen = atr[0].length;
		
		for (int i = 0; i < atrCount; i++) {
			for (int j = 0; j < atrLen; j++) {
				ret[i*atrLen + j] = atr[i][j];
			}
		}
		return ret;
	}
	
	public void plotDCT(){

		Plot3DPanel plot = new Plot3DPanel();
		
		plot.addScatterPlot("dct", x, y, z);
		
		JFrame frame = new JFrame("plane");
		frame.setSize(600, 600);
		frame.setContentPane(plot);
		frame.setVisible(true);
		
	}
	
	
	public void plotWave(){ 
		
		Plot2DPanel plot = new Plot2DPanel();
	
		JFrame frame = new JFrame("sound wave");
		
		double[] tx = new double[n];
		double[] ty = new double[n];


		for (int i = 0; i < in.length; i++) {
			tx[i] = i;
			ty[i] = in[i];
		}
		
		plot.addLegend("SOUTH");
		plot.addLinePlot("DCT", tx, ty);

		frame.setSize(600, 600);
		frame.setContentPane(plot);
		frame.setVisible(true);
	}
}
